package com.mgy.example.service.common.lock.aop;

import com.mgy.example.annotation.ZooKeeperLock;
import com.mgy.example.service.common.config.zk.CuratorConfig;
import com.mgy.example.utils.LockUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class ZooKeeperLockAspect {

    @Autowired
    private CuratorConfig curatorConfig;
    @Autowired
    private CuratorFramework curatorFramework;

    @Pointcut("@annotation(com.mgy.example.annotation.ZooKeeperLock)")
    public void distributedLockPointcut() {

    }

    @Around(value = "distributedLockPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        ZooKeeperLock zooKeeperLock = methodSignature.getMethod().getAnnotation(ZooKeeperLock.class);
        String[] parameterNames = methodSignature.getParameterNames();
        Class[] parameterTypes = methodSignature.getMethod().getParameterTypes();
        Object[] parameterValues = joinPoint.getArgs();
        //获取锁的名称
        String lockPath = LockUtil.getLockName(zooKeeperLock.lockPath(), zooKeeperLock.fieldName(), parameterNames, parameterTypes, parameterValues);
        long waitTime = zooKeeperLock.waitTime();
        String prefix = zooKeeperLock.prefix();
        String path = StringUtils.isBlank(lockPath) ? curatorConfig.getLockRoot() : curatorConfig.getLockRoot() + "/" + prefix + lockPath;
        InterProcessMutex mutex = new InterProcessMutex(curatorFramework, path);
        try {
            //加锁
            if (waitTime > 0) {
                mutex.acquire(waitTime, TimeUnit.SECONDS);
            } else {
                mutex.acquire();
            }
            //执行业务方法
            return joinPoint.proceed();
        } finally {
            //解锁
            mutex.release();
        }
    }

}
